﻿package net.wangit.support.action;

import java.util.HashMap;
import java.util.Map;

import net.wangit.LabelUtil;
import net.wangit.MapList;
import net.wangit.context.ActionContext;
import net.wangit.context.ActionContextHelper;
import net.wangit.context.ActionResult;
import net.wangit.framework.action.ActionUtil;
import net.wangit.framework.session.AgileSession;
import net.wangit.jdbc.DB;
import net.wangit.jdbc.ServerAccessException;
import net.wangit.jdbc.Transaction;
import net.wangit.jdbc.executable.ConstraintException;
import net.wangit.jdbc.executable.DirtyRowException;
import net.wangit.jdbc.table.TableConfigurationException;
import net.wangit.support.Action;
import net.wangit.util.Checker;
import net.wangit.util.StringUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 实现了事务处理，并且处理主键、外键、脏数据等数据操作异常。
 * 事务回滚的条件：执行结果失败（ActionResult.isSuccessful()）或接收到异常。
 * 子类需要实现 doAction方法。 
 * @author watson
 * Feb 14, 2010
 */
public abstract class TransactionAction implements Action {
	private static final Log log = LogFactory.getLog(TransactionAction.class);
	
	// 完成事务处理，处理的DB对象通过getDB创建。
	public ActionContext execute(ActionContext ac) throws Exception {
		ActionResult result = ac.getActionResult();

		DB db = getDB(ac);
		if (db == null) {
			result.setSuccessful(false);
			return ac;
		}
		Transaction transaction = null;
		try {
			transaction = db.beginTransaction();
			doAction(db, ac);
		} catch (ServerAccessException e) {
			result.setSuccessful(false);
			result.addError(LabelUtil.get(ac, "system",
					"action.server_access_error"));
			log.error(e);
		} catch (TableConfigurationException e) {
			result.setSuccessful(false);
			result.addError(LabelUtil.get(ac, "system",
					"action.table_configuration_error"));
			log.error(e);
		} catch (DirtyRowException e) {
			result.setSuccessful(false);
			result.addError(LabelUtil.get(ac, "system", "action.dirty"));
		} catch (ConstraintException e) {
			result.setSuccessful(false);
			setConstraintError(ac, result, e);
		} catch (Exception e) {
			result.setSuccessful(false);
			String msg = e.getMessage();
			if ((!(Checker.isEmpty(msg)))
					&& (msg.toLowerCase().indexOf(" foreign key ") >= 0)) {
				result.addError(LabelUtil.get(ac, "system", "validation.fk"));
			}
			log.error("do action failed: " + super.getClass().getName(), e);
		} finally {
			if (transaction != null) {
				if (result.isSuccessful())
					transaction.commit();
				else {
					transaction.rollback();
				}
			}
			if (db != null) {
				db.close();
			}

		}
		return ac;
	}

	//取得数据访问对象，此DB对象将实现事务处理。
	protected DB getDB(ActionContext ac) {
		return ActionUtil.getActionDB(ac);
	}

	private void setConstraintError(ActionContext ac, ActionResult result,
			ConstraintException ce) {
		String message = ce.getMessage();
		String[] markInfo = StringUtil.split(message, ",");
		if ((markInfo != null) && (markInfo.length > 2)) {
			result.addError(LabelUtil.get(ac, "system", "validation.pk"));

			String unitId = markInfo[0];
			int rowIndex = Integer.parseInt(markInfo[1]);
			MapList unitInvalidFields = new MapList();
			for (int i = 2; i < markInfo.length; ++i) {
				unitInvalidFields.put(rowIndex, markInfo[i], "");
			}
			Map invalidFields = new HashMap();
			invalidFields.put(unitId, unitInvalidFields);
			AgileSession session = ActionContextHelper.getSession(ac);
			session.setInvalidFields(invalidFields);
		} else {
			result.addError(LabelUtil.get(ac, "system", "validation.pk",
					message));
		}
	}
	
	// 执行业务逻辑。
	public abstract void doAction(DB paramDB, ActionContext paramActionContext)
			throws Exception;
}